Sortie de git 2.9

Posté par  . Édité par M5oul, Matthieu Moy, Nairwolf, palm123 et Yves Bourguignon. Modéré par ZeroHeure. Licence CC By‑SA.
71
22
juin
2016
Gestion de versions

git 2.9 est sorti le 13 juin 2016. Pour rappel, git est un gestionnaire de version décentralisé, originellement développé par Linus Torvalds pour versionner les sources du noyau Linux. Depuis, ce gestionnaire de version est devenu très populaire parmi les projets open-source, comme en témoigne le succès des plateformes basées sur cet outil, comme GitHub ou Gitlab, ainsi que les projets de toutes tailles auto-hébergés utilisant git.

Dans cette dépêche nous nous proposons de revenir sur quelques-uns des changements apportés par cette version.

Git logo

Sommaire

Améliorations de la commande diff

Lisibilité des diff

La relecture de diff est parfois rendue fastidieuse par leur côté asémantique. Le véritable changement introduit par un commit, comme par exemple l’ajout d’un bloc de code, n’apparaît pas clairement dans un diff représenté ainsi :

 function exemple (tab) {

     tab.forEach(element => {
+        action1(element);
+    });
+
+    tab.forEach(element => {
         action2(element);
     });

Cette nouvelle version améliore le rendu des diff en rendant leur détection et coloration plus intelligentes (par détection des lignes vides). L’exemple précédent devient ainsi :

 function exemple (tab) {

+    tab.forEach(element => {
+        action1(element);
+    });
+
     tab.forEach(element => {
         action2(element);
     });

Cette fonctionnalité s’active avec l’option --compaction-heuristic ou avec la configuration diff.compactionHeuristic. Cette fonctionnalité est toutefois encore expérimentale.

Pour rappel dans les versions précédentes de git, dans certains cas, les diff pouvaient être plus clairs et générer moins de conflits par l’utilisation de l’algorithme patience via l’option --patience ; cette possibilité est toujours présente.

Renommages et diff

Une autre amélioration apportée par cette version est la détection des renommages par la commande diff qui se fait désormais par défaut. Le comportement peut être configuré via la clé diff.renames.

Amélioration de la commande log

Le format de sortie de la commande git log expanse désormais les tabulations en affichant le message de commit. En effet, git log affiche ce message avec une indentation de quatre espaces, ce qui cassait l'affichage des messages utilisant les tabulations pour l'alignement. Il est possible d'utiliser l'option --no-expand-tabs pour désactiver ce comportement.

Amélioration de la commande tag

git tag peut désormais créer un tag annoté sans utiliser explicitement l'option -a (ou -s) lorsqu’un message d’étiquetage est donné. Une nouvelle clé de configuration tag.forceSigneAnnotated peut être utilisée pour que la commande crée un tag signé dans cette situation.

Tester chaque commit lors d’un rebase

Pendant un rebase interactif git rebase -i il était déjà possible d’exécuter une commande entre deux commits en ajoutant une ligne avec le préfixe x ou exec puis la commande. On pouvait insérer une telle ligne après chaque commit avec par exemple :

$ git rebase -i --exec "make test"

Cela ouvre plusieurs possibilités, comme lancer un jeu de tests sur chaque commit pour corriger plusieurs défauts (là où un bisect devrait être utilisé pour chaque défaut), compiler le code pour vérifier la syntaxe ou encore lancer du linting et améliorer la qualité du code ; le rebase est mis en pause si la commande utilisée renvoie une erreur. Un git rebase --continue reprend l’opération à tout moment.

L'option --exec (ou -x) est maintenant utilisable sans spécifier explicitement -i, ce qui permet d'économiser quelques caractères sur la commande et évite de lancer inutilement l'éditeur de texte.

Amélioration de la commande merge

Avant cette nouvelle version, la commande git merge permettait par défaut de fusionner deux branches sans aucune base commune dans leurs historiques respectifs. Ce comportement par défaut créait un historique parallèle dans le projet qui fusionnait une branche d’un autre projet, faisant grossir de manière inutile l’historique du projet. Le comportement par défaut a été changé dans cette version afin de ne pas autoriser la fusion de deux branches sans rapport. Bien sûr il est toujours possible de l’autoriser via l’option --allow-unrelated-histories dans les rares cas où ce comportement est souhaité.

Cette option a aussi été ajoutée à la commande git pull afin d’être passée au merge sous-jacent.

Améliorations dans la gestion des sous-modules

Parallélisation

Dans la version précédente, la possibilité de récupérer les sous-modules en parallèle avait été ajoutée via l’option --jobs=<n> lors d’un fetch. Dans cette version, cette possibilité a été étendue aux opérations de clonage et de mise à jour. Si vous souhaitez toujours paralléliser ces opérations sur les sous-modules, cela se configure via la clé submodule.fetchJobs.

Migration de code

Afin de profiter de ce nouveau framework de parallélisation, la majeure partie du code de submodule update a été migrée en C. D’autres parties de code concernant les sous-modules ont aussi été portées en C. La logique des commandes git submodule était précédemment écrite en script shell.

Amélioration de la commande describe

La commande git describe --contains, qui donne une description d’un commit par sa position relative au tag le plus proche qui le contient, a tendance à générer un nom quelque peu sibyllin et surtout difficile à expliquer. La sortie de cette commande est composée de deux parties :

  1. le tag le plus proche contenant le commit ;
  2. le nombre de commit pour l’atteindre.

Ce qui ressemble généralement à cette sortie : my-tag~13. Le problème de l’ancien comportement est que si un proche descendant du commit a été récemment taggé, alors ce nouveau tag est pris comme référence dans la sortie de la commande, à la place du tag le plus ancien qui le contenait. Dans cette version, le comportement a été revu afin d’être plus clair à interpréter. Cette commande retourne donc maintenant « la description d’un commit par rapport au tag le plus ancien (chronologiquement) qui le contient ».

Par exemple, la révision aed06b9 (qui est utilisée dans le rapport de bug à l’origine du changement) du noyau Linux était auparavant décrite comme v4.6-rc1~9^2~792, ce qui est correct au sens où cette révision est bien l’ancêtre au 792e degré du deuxième parent de l’ancêtre au 9e degré du tag v4.6-rc1, mais trompeur, car cette révision est en réalité très ancienne et la description incluant v4.6-rc1 laissait entendre que le commit avait été introduit juste avant la version 4.6-rc1. Avec Git 2.9, le résultat est v3.13-rc1~65^2^2~42, et effectivement v3.13-rc1 est le plus ancien tag postérieur à la révision.

Aller plus loin

  • # Des tabs à 4 espaces

    Posté par  (site web personnel) . Évalué à -3.

    Il y en a qui virerai leur copine pour moins que ça (indice: S03E06)

  • # Chouette dépêche

    Posté par  . Évalué à 5.

    Merci pour cette dépêche, on y apprend plein de trucs. Notamment que parfois, être un cousin au 972eme degré est possible, mais trompeur :)

  • # git rebase --exec

    Posté par  (site web personnel) . Évalué à 10.

    Un peu hors sujet, mais un truc sympa que l'ont peut faire avec --exec pour ceux qui font du C++ ou du C (ou même du Javascript)

    git rebase --exec "git-clang-format HEAD^"
    

    git-clang-format étant un script fourni avec clang, qui va reformater le code (selont les règles décrites dans le fichier .clang-format présent au bon endroit.)
    Pour chaque commit, ça va reformater les lignes qui ont changées. Quand un commit a été modifier, ça s'arrête et vous pouvez faire

    git diff                  # voir les changements
    git commit -a --amend     # les appliquer 
    git rebase --continue     # continuer le rebase
    
  • # Git sur https

    Posté par  (site web personnel) . Évalué à -3.

    Des gens ont réussi une configuration simple sur https de git ?

    Avec (au hasard) :
    - gitweb pour un listing joli
    - accès en lecture anonyme
    - accès en écriture avec authentification

    Parce que j'ai tenté pas mal de combinaisons, DAV échoue sur les opérations MOVE avec une 502 pour on se sait quelle raison.

    Et pour git-http-backend, il faut utiliser deux AliasMatch et un ScriptAliasMatch et se baser sur une détection immonde du paramètre git-receive-pack dans QUERY_STRING ou REQUEST_URI…

    Sans oublier un git config http.receivepack true sur tous les dépôts…

    Tout ça pour juste autoriser l'accès en lecture seule…

    Je parles pas des centaines de tutoriaux buggués sur internet qui ne fonctionnent plus sur apache 2.4.x et git 2.9.

    • [^] # Re: Git sur https

      Posté par  (site web personnel) . Évalué à 7.

      Première chose : évites absolument le WebDAV. C'est un hack intéressant quand tu ne peux pas héberger de CGI (rien de spécifique à Git sur le serveur, juste un serveur webdav et ça suffit), mais c'est beaucoup plus lent que git-http-backend et c'est aussi plus buggé (lent => peu d'utilisateurs => peu de volontaires pour corriger les bugs).

      Et pour git-http-backend, il faut utiliser deux AliasMatch et un ScriptAliasMatch et se baser sur une détection immonde du paramètre git-receive-pack dans QUERY_STRING ou REQUEST_URI…

      Si tu veux héberger un dépôt Git utilisable par un client git et du gitweb utilisable par un navigateur web sur la même URL, tu vas bien être obligé de dire quelque part « ça, c'est pour git-http-backend et ça c'est pour gitweb ».

      Sans oublier un git config http.receivepack true sur tous les dépôts…
      Tout ça pour juste autoriser l'accès en lecture seule…

      Si tu dois positionner la même variable sur tous les dépôts, utilises ~/.gitconfig ou /etc/gitconfig.

      Je ne peux que te conseiller de suivre à la lettre la doc de git-http-backend et de rapporter les éventuels bugs sur la mailing-list (mais si c'est juste pour râler que c'est trop dur sans poser de vraie question, tu auras peu de chance d'avoir de l'aide …).

      • [^] # Re: Git sur https

        Posté par  (site web personnel) . Évalué à 1.

        Ce qui m'embête c'est que soit t'as un vhost comme ceci, avec un hack immonde de ré-écriture de l'en-tête Destination, parce qu'à priori un dev apache a pas voulu corriger ce bug en 2008… : https://bz.apache.org/bugzilla/show_bug.cgi?id=45449

        <VirtualHost *:443>
                ServerAdmin user@example.com
                ServerName git.example.com
        
                <Directory /var/www/git>
                        DAV on
                        Options ExecCgi FollowSymLinks
        
                        # Fix dav header
                        RequestHeader edit Destination ^https: http: early
        
                        # Gitweb config
                        AddHandler cgi-script .cgi
                        DirectoryIndex gitweb.cgi
                        SetEnv GITWEB_CONFIG gitweb.conf
        
                        AuthType Basic
                        AuthName "Git repositories"
                        AuthUserFile /var/www/git/.htpasswd
        
                        Require method GET OPTIONS PROPFIND
                        <LimitExcept GET OPTIONS PROPFIND>
                                Require valid-user
                        </LimitExcept>
                </Directory>
        </VirtualHost>
        

        Soit t'es obligé d'avoir un truc comme ça :

        <VirtualHost *:443>
                ServerAdmin user@example.com
                ServerName git.example.com
        
                DocumentRoot /var/www/git
        
                <IfModule alias_module>
                        AliasMatch "^/(.*/objects/[0-9a-f]{2}/[0-9a-f]{38})$" /var/www/git/$1
                        AliasMatch "^/(.*/objects/pack/pack-[0-9a-f]{40}.(pack|idx))$" /var/www/git/$1
                        ScriptAliasMatch "^/(.*/(HEAD|info/refs|objects/info/[^/]+|git-(upload|receive)-pack))$" /var/www/git/git-http-backend/$1
                </IfModule>
        
                <Directory /var/www/git>
                        Options ExecCgi FollowSymLinks
        
                        # Git http backend config
                        SetEnv GIT_PROJECT_ROOT /var/www/git
                        SetEnv GIT_HTTP_EXPORT_ALL
        
                        # Gitweb config
                        AddHandler cgi-script .cgi
                        DirectoryIndex gitweb.cgi
                        SetEnv GITWEB_CONFIG gitweb.conf
        
                        AuthType Basic
                        AuthName "Git repositories"
                        AuthUserFile /var/www/git/.htpasswd
        
                        # Allow non push git request
                        Require expr "(%{QUERY_STRING} !~ /service=git-receive-pack/) && (%{REQUEST_URI} !~ /git-receive-pack$/)"
                        # Allow push for valid user
                        Require valid-user
                </Directory>
        </VirtualHost>
        

        Le problème c'est que rien ne te garantis, que un jour quelqu'un autorisera pas a pousser des données via autre chose que git-receive-pack, déjà il y a deux méthodes pour pousser des données…

    • [^] # Re: Git sur https

      Posté par  . Évalué à 4.

      https://www.scm-manager.org/

      Tu le lances, tu déclares tes dépôts et c'est parti !

      Accessoirement tu installes ça sur un serveur Tomcat le connecte à un annuaire (Crowd pour nous) e ça tient la charge easy pour administrer des dépôts d'une entreprise.
      Testé et approuvé dans une DSI de 500 personnes avec plus de 1000 dépôts dont certains d'une taille de 4Go.

      Enjoy !!!

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.